home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Programming / tek / doc / manuals / tasks next >
Encoding:
Text File  |  2001-05-21  |  8.2 KB  |  261 lines

  1.  
  2. TEKLIB MULTITASKING
  3. ------------------------------------------------------------
  4.  
  5. making an application user-friendly and snappy often
  6. requires that different jobs are distributed over multiple
  7. threads; that means, a program's flow of execution is
  8. splitted into several paths, running simultaneously.
  9.  
  10. preemptive multitasking means that the operating system
  11. decides when your current thread of execution will be
  12. interrupted and the control is being handed over to another
  13. thread.  threads normally execute consecutively only for a
  14. short period of time, usually in the range of milli- or
  15. microseconds.
  16.  
  17. you, the programmer of a multithreaded application, don't
  18. have much control over this scheduling procedure, and you
  19. must take care that your application does not run into
  20. so-called race conditions.
  21.  
  22. a race condition is when one thread of execution inside your
  23. application depends on the results from another thread, but
  24. you did not take precautions for the case that the results
  25. from that other thread may not have arrived in time, when
  26. you expect them.  the less likely that case, the bigger the
  27. problem.
  28.  
  29. race conditions are hard to track down.  your code may work
  30. in 99,99% of all cases, and crash your application
  31. otherwise.  or even worse, it may work in 100% of all cases
  32. on your computer, and never on another computer (or another
  33. operating system).
  34.  
  35. means to avoid race conditions are called synchronization
  36. mechanisms.  synchronization is crucial for most
  37. multithreaded applications, because there will almost for
  38. sure be a point in your program where the results from
  39. different threads need to be merged together.
  40.  
  41. synchronization is even more important inside of TEKlib.
  42. you don't have access to any of the kernel's scheduling
  43. parameters (such as priorities, nice-values and alike), and
  44. the behavior of the underlying kernel may vary drastically
  45. across different platforms.
  46.  
  47. TEKlib greatly supports you in creating multithreaded
  48. designs.  even better, it makes it easier than most other
  49. operating systems and programming environments do.  use its
  50. well-defined mechanisms right, and your multithreaded
  51. applications will be stable, fast, and fault-tolerant as
  52. well.
  53.  
  54. let's have a look on a multithreaded program.  our first job
  55. is to setup a common TEKlib environment.  this is achieved
  56. as follows:
  57.  
  58.  
  59. #include <tek/exec.h>
  60.  
  61. void main(void)
  62. {
  63.     TAPTR basetask = TCreateTask(TNULL, TNULL, TNULL);
  64.     if (basetask)
  65.     {
  66.         /* ... party goes here ... */
  67.  
  68.         TDestroy(basetask);
  69.     }
  70. }
  71.  
  72.  
  73. most TEKlib applications have a program startup like this.
  74. the function TCreateTask(TNULL, TNULL, TNULL) will setup a
  75. lot of internal magic, but most obviously, it returns a task
  76. handle.  that task handle is called the basetask or base
  77. context.  most TEKlib functions relate to a context handle,
  78. we don't have one when the application is entered, and so we
  79. have to create it first.
  80.  
  81. a potential point of confusion may be that TCreateTask() is
  82. the same function as for creating child tasks.  that's not
  83. the case here; with the three TNULL arguments, TCreateTask()
  84. will return only a base context handle for the newly entered
  85. application, but it does not create a new thread of
  86. execution.
  87.  
  88. please note that we check for the return value of
  89. TCreateTask().  let it be extremely unlikely that this
  90. function fails; but when it fails, your application will
  91. crash miserably if you don't check it.  it would be nonsense
  92. to demonstrate synchronization mechanisms for avoiding race
  93. conditions, when we didn't catch the obvious reasons for
  94. failure before.  all demonstrations in this manual will
  95. always check for successful completion of all functions, and
  96. may it be nauseating routine.  that's the C language, you
  97. must deal with it.
  98.  
  99. let's continue with the multitasking example.  now that we
  100. have a base task, we can actually create a sub (or child)
  101. task.  this example does not only setup a child task, it
  102. also demonstrates the first of a variety of synchronization
  103. mechanisms.
  104.  
  105.  
  106. #include <tek/exec.h>
  107.  
  108. TVOID childfunc(TAPTR task)
  109. {
  110.     TWait(task, TTASK_SIG_ABORT);
  111. }
  112.  
  113. void main(void)
  114. {
  115.     TAPTR basetask = TCreateTask(TNULL, TNULL, TNULL);
  116.     if (basetask)
  117.     {
  118.         TAPTR childtask = TCreateTask(basetask, childfunc, TNULL);
  119.         if (childtask)
  120.         {
  121.             TTimeDelayF(basetask, 3.5f);
  122.             TSignal(childtask, TTASK_SIG_ABORT);
  123.             TDestroy(childtask);
  124.         }
  125.         TDestroy(basetask);
  126.     }
  127. }
  128.  
  129.  
  130. this time we pass the basetask handle and a child task
  131. function entry to TCreateTask(), thus letting it actually
  132. create a new thread of execution.
  133.  
  134. the next function in the parent's thread of execution,
  135. TTimeDelayF(), causes the program to wait for 3.5 seconds.
  136. note that the function TTimeDelayF() depends on a task (as
  137. many TEKlib functions do), and that the postponed 'F'
  138. indicates that you may pass a float value as an argument.
  139. TTimeDelayF() is actually a convenience macro for the more
  140. complicated underlying function TTimeDelay().
  141.  
  142. meanwhile, the child task has probably entered its function,
  143. and reached the function TWait().  this function causes the
  144. current context (or task, or thread of execution) to go to
  145. sleep, and to no longer consume any CPU time.  arguments to
  146. TWait() are the context it is currently running in, and a
  147. set of so-called 'signals' to wait for.
  148.  
  149. in the end, a signal is a synchronization mechanism.  but
  150. first of all, it's just a bit in a task's context, with a
  151. reserved meaning.  upon a task's creation, its set of
  152. signals is clear.  one or more of these signals (each with a
  153. reserved meaning) may be submitted from another task, and
  154. these signal bits will remain set until a function is called
  155. that clears it.
  156.  
  157. TWait() causes its context to got to sleep, waiting for the
  158. specified set of signals.  when any of the signals being
  159. waited for arrive, they will be cleared from the task's
  160. current set of signals, and TWait() returns.
  161.  
  162. TEKlib predefines the signal bit TASK_SIG_ABORT with the
  163. reserved meaning "abort this task", because task abortion is
  164. required quite often.  so
  165.  
  166.             TSignal(childtask, TTASK_SIG_ABORT);
  167.  
  168. will obviously submit that signal to the child task, the
  169. child task wakes up, clears the signal TTASK_SIG_ABORT from
  170. its context, and continues execution.  since that was the
  171. last and only operation in its function, it will leave
  172. through the function exit, and go into a zombie-like state -
  173. i.e.  "probably dead, but may still be there".
  174.  
  175. although the child task MAY have finished execution
  176. (remember the race-conditions?), there is still that child
  177. task handle in the parent context, and you MUST destroy that
  178. handle.  that will not only free the task's internal
  179. buffers, but also ensures that the underlying thread is
  180. actually gone before TDestroy() returns.
  181.  
  182. on the other hand, TEKlib does in no way allow you to 'kill'
  183. a task with brute force.  TDestroy() won't actually destroy
  184. the task's thread of execution, it can only destroy the
  185. task's handle once the underlying thread of execution has
  186. concluded.  if your task is caught in some kind of endless
  187. loop, doesn't react to signals or timeouts, then your
  188. application is broken.  tasks must always leave gently
  189. through their function exit.
  190.  
  191. this example will block, and never return:
  192.  
  193.  
  194. #include <tek/exec.h>
  195.  
  196. TVOID childfunc(TAPTR task)
  197. {
  198.     TWait(task, TTASK_SIG_ABORT);
  199. }
  200.  
  201. void main(void)
  202. {
  203.     TAPTR basetask = TCreateTask(TNULL, TNULL, TNULL);
  204.     if (basetask)
  205.     {
  206.         TAPTR childtask = TCreateTask(basetask, childfunc, TNULL);
  207.         if (childtask)
  208.         {
  209.             TDestroy(childtask);
  210.         }
  211.         TDestroy(basetask);
  212.     }
  213. }
  214.  
  215.  
  216. since the abortion signal is never sent, never caught,
  217. TWait() never returns, and TDestroy() will hang forever.
  218. you may, however, limit the timespan for the child task to
  219. wait for a signal:
  220.  
  221.  
  222. #include <tek/exec.h>
  223.  
  224. TVOID childfunc(TAPTR task)
  225. {
  226.     TTIME timeout;
  227.     TFTOTIME(3.5f, &timeout);
  228.  
  229.     if (TTimedWait(task, TTASK_SIG_ABORT, &timeout) == 0)
  230.     {
  231.         printf("timeout expired.\n");
  232.     }
  233.     else
  234.     {
  235.         printf("caught signal.\n");
  236.     }
  237. }
  238.  
  239. void main(void)
  240. {
  241.     TAPTR basetask = TCreateTask(TNULL, TNULL, TNULL);
  242.     if (basetask)
  243.     {
  244.         TAPTR childtask = TCreateTask(basetask, childfunc, TNULL);
  245.         if (childtask)
  246.         {
  247.             TDestroy(childtask);
  248.         }
  249.         TDestroy(basetask);
  250.     }
  251. }
  252.  
  253.  
  254. in this example, we use the timed version of TWait().
  255. please note that you must supply a TTIME structure.  there
  256. is no convenience macro like TTimeDelayF() in that case,
  257. sorry, but a timeout structure may be initialized with
  258. another float support macro, TFTOTIME().
  259.  
  260. to be continued...
  261.